package zhongbo.javaweb.instagram.util.thread;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.TimeUnit;

import static zhongbo.javaweb.instagram.util.PerformanceUtil.countEndStr;
import static zhongbo.javaweb.instagram.util.PerformanceUtil.countStart;

/**
 * 说明：
 * 仿进度条的任务执行器
 *
 * @author zhongboWork
 * @version 1.0
 * @since 2021-12-17 10:38
 */
@Getter
@Slf4j
public class ProgressRunner<T> extends Observable implements Runnable {

    private String progressName;

    private int totalCount;

    private int currentCount;

    private int percentCount;

    private boolean isPaused;

    private boolean isStopped;

    private long startTimeMs;

    private long pastMs;

    private Collection<T> targetList;

    private ProgressProcessor<T> processor;

    private Observable observable;

    public ProgressRunner(Collection<T> targetList, String progressName, ProgressProcessor<T> processor) {
        this.targetList = targetList;
        this.progressName = progressName;
        this.processor = processor;
        initProgressRunner();
    }

    @Override
    public void run() {
        log.info("{} 执行开始", progressName);
        countStart(this);
        try {
            UUID uuid = UUID.randomUUID();
            Iterator<T> iterator = targetList.iterator();
            for (int i = 0; i < targetList.size(); i++) {
                T t = iterator.next();
                while (isPaused) {
                    TimeUnit.SECONDS.sleep(1);
                }
                if (isStopped) {
                    break;
                }
                countStart(uuid);
                currentCount++;
                processor.process(t, i);
                notifyObservers(new ProgressMessage<>(false, t));
                updatePercent();
                if (log.isDebugEnabled()) {
                    log.debug("{} 单项执行完成,进度 {} of {}, 耗时 {}", progressName, currentCount, totalCount, countEndStr(uuid));
                }
            }
        } catch (Exception e) {
            log.error("{} 异常结束, 运行时间 {}", progressName, countEndStr(this), e);
        }
        log.info("{} 执行完成, 耗时 {}", progressName, countEndStr(this));
        notifyObservers(new ProgressMessage<T>(true, null));
    }

    private void initProgressRunner() {
        if (targetList == null) {
            throw new RuntimeException("ProgressRunner 使用错误,未指定 targetList!");
        }
        if (processor == null) {
            throw new RuntimeException("ProgressRunner 使用错误,未指定 processor!");
        }
        this.totalCount = targetList.size();
        this.currentCount = 0;
        if (this.progressName == null) {
            this.progressName = this.getClass().getSimpleName() + "_" + UUID.randomUUID().toString().substring(0, 4);
        }
        updatePercent();
        this.isPaused = false;
        this.startTimeMs = System.currentTimeMillis();
    }

    public void stop() {
        this.isStopped = true;
    }

    public void pause() {
        this.isPaused = true;
    }

    public void resume() {
        this.isPaused = false;
    }

    private void updatePercent() {
        this.percentCount = this.currentCount / this.totalCount;
    }

    public long getPastMs() {
        this.pastMs = System.currentTimeMillis() - this.startTimeMs;
        return this.pastMs;
    }

}
